

import UIKit

class SpinnerView: UIView {
    
    let kAnimationStrokeKey:String! = "animationStrokeKey"
    let kAnimationRotationKey:String! = "animationRotationKey"
    
    var _progressLayer:CAShapeLayer!
    var progressLayer:CAShapeLayer {
        get{
            if (_progressLayer == nil){
                _progressLayer = CAShapeLayer()
                _progressLayer.strokeColor = self.tintColor.CGColor
                _progressLayer.fillColor = nil
                _progressLayer.lineWidth = 2
            }
            return _progressLayer
        }
        set{ self._progressLayer = newValue }
    }
    
    var isAnimating:Bool = false
    var _hidesWhenStopped:Bool = true
    let timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
    
    var lineWidth:CGFloat{
        get{ return self.progressLayer.lineWidth }
        set{ self.progressLayer.lineWidth = newValue
            updatePath() }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        initialize()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        initialize()
    }
    
    func initialize() {
        self.layer.addSublayer(self.progressLayer)
        
        self.progressLayer.frame = CGRectMake(0, 0, CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds))
        updatePath()
        
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(SpinnerView.resetAnimations), name: UIApplicationDidBecomeActiveNotification, object: nil)
    }
    
    deinit{
        NSNotificationCenter.defaultCenter().removeObserver(self, name: UIApplicationDidBecomeActiveNotification, object: nil)
    }
    
    override func tintColorDidChange() {
        super.tintColorDidChange()
        self.progressLayer.strokeColor = self.tintColor.CGColor
    }
    
    func resetAnimations() {
        if self.isAnimating {
            stopAnimating()
            startAnimating()
        }
    }
    
    func setAnimating(animate:Bool) {
        animate ? startAnimating() : stopAnimating()
    }
    
    func startAnimating() {
        if self.isAnimating {
            return
        }
        
        let animation = CABasicAnimation()
        animation.keyPath = "transform.rotation"
        animation.duration = 4.0
        animation.fromValue = 0
        animation.toValue = 2*M_PI
        animation.repeatCount = Float(NSIntegerMax)
        self.progressLayer.addAnimation(animation, forKey: kAnimationRotationKey)
        
        let headAnimation = CABasicAnimation()
        headAnimation.keyPath = "strokeStart";
        headAnimation.duration = 1.0
        headAnimation.fromValue = 0
        headAnimation.toValue = 0.25
        headAnimation.timingFunction = self.timingFunction
        
        let tailAnimation = CABasicAnimation()
        tailAnimation.keyPath = "strokeEnd"
        tailAnimation.duration = 1.0
        tailAnimation.fromValue = 0
        tailAnimation.toValue = 1.0
        tailAnimation.timingFunction = self.timingFunction
        
        let endHeadAnimation = CABasicAnimation()
        endHeadAnimation.keyPath = "strokeStart"
        endHeadAnimation.beginTime = 1.0
        endHeadAnimation.duration = 0.5
        endHeadAnimation.fromValue = 0.25
        endHeadAnimation.toValue = 1.0
        endHeadAnimation.timingFunction = self.timingFunction
        
        let endTailAnimation = CABasicAnimation()
        endTailAnimation.keyPath = "strokeEnd"
        endTailAnimation.beginTime = 1.0
        endTailAnimation.duration = 0.5
        endTailAnimation.fromValue = 1.0
        endTailAnimation.toValue = 1.0
        endTailAnimation.timingFunction = self.timingFunction
        
        let animations = CAAnimationGroup()
        animations.duration = 1.5
        animations.animations = [headAnimation, tailAnimation, endHeadAnimation, endTailAnimation]
        animations.repeatCount = Float(NSIntegerMax)
        self.progressLayer.addAnimation(animations, forKey: kAnimationStrokeKey)
        
        self.isAnimating = true
        
        if _hidesWhenStopped {
            self.hidden = false
        }
    }
    
    func stopAnimating() {
        if !self.isAnimating {
            return
        }
        
        self.progressLayer.removeAnimationForKey(kAnimationRotationKey)
        self.progressLayer.removeAnimationForKey(kAnimationStrokeKey)
        self.isAnimating = false
        
        if _hidesWhenStopped {
            self.hidden = true
        }
    }
    
    //MARK: - Private
    func updatePath() {
        let aradius = min(CGRectGetWidth(self.bounds)/2, CGRectGetHeight(self.bounds) / 2) - self.progressLayer.lineWidth / 2
        let astartAngle = CGFloat(0)
        let aendAngle = CGFloat(2*M_PI)
        let path:UIBezierPath = UIBezierPath(arcCenter: center, radius: aradius, startAngle: astartAngle, endAngle: aendAngle, clockwise: true)
        
        self.progressLayer.path = path.CGPath
        self.progressLayer.strokeStart = 0.0
        self.progressLayer.strokeEnd = 0.0
    }
    
    func setHidesWhenStopped(hidesWhenStopped:Bool){
        _hidesWhenStopped = hidesWhenStopped
        self.hidden = !self.isAnimating && hidesWhenStopped
    }
    
}


class RotationButton: UIControl {

    var defaultW:CGFloat!
    var defaultH:CGFloat!
    var defaultR:CGFloat!
    var scale:CGFloat!
    var bgView:UIView!
    
    var spinnerView:SpinnerView!
    var forDisplayButton:UIButton!
    
    var btnBackgroundImage:UIImage?
    
    var _isLoading:Bool = false
    var isLoading:Bool{
        get{ return _isLoading }
        set{
            _isLoading = newValue
            if _isLoading {
                self.startLoading()
            }else{
                self.stopLoading()
            }
        }
    }
    
    var _contentColor:UIColor!
    var contentColor:UIColor {
        get{
            return _contentColor
        }
        set{
            _contentColor = newValue
        }
    }
    
    var _progressColor:UIColor!
    var progressColor:UIColor {
        get{
            return _progressColor
        }
        set{
            _progressColor = newValue
        }
    }
    
    override var frame: CGRect {
        get {
            let _frame = super.frame

            return _frame
        }
        set {
            super.frame = newValue
        }
    }
    
    override var selected: Bool{
        get{return super.selected}
        set{
            super.selected = newValue
            self.forDisplayButton.selected = newValue
        }
    }
    
    override var highlighted: Bool{
        get{return super.highlighted}
        set{
            super.highlighted = newValue
            self.forDisplayButton.highlighted = newValue
        }
    }
    
    init(frame: CGRect, color:UIColor) {
        super.init(frame: frame)
        initSettingWithColor(color)
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        initSettingWithColor(self.tintColor)
    }
    
    func imageWithColor(color:UIColor, cornerRadius:CGFloat) -> UIImage{
        let rect = CGRectMake(0, 0, cornerRadius*2+10, cornerRadius*2+10)
        
        let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius)
        path.lineWidth = 0
        
        UIGraphicsBeginImageContextWithOptions(rect.size, false, 0)
        let context = UIGraphicsGetCurrentContext()
        CGContextSetFillColorWithColor(context, color.CGColor)
        
        path.fill()
        path.stroke()
        path.addClip()
        
        let image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return image;
    }
    
    func initSettingWithColor(color:UIColor) {
        self.scale = 1.2
        self.bgView = UIView(frame: self.bounds)
        self.bgView.backgroundColor = color
        self.bgView.userInteractionEnabled = false
        self.bgView.hidden = true
        self.bgView.layer.cornerRadius = CGFloat(self.bounds.size.height/2)
        self.addSubview(self.bgView)
        
        defaultW = self.bgView.frame.width
        defaultH = self.bgView.frame.height
        defaultR = self.bgView.layer.cornerRadius
        
        self.spinnerView = SpinnerView(frame: CGRectMake(0 , 0, defaultH*0.8, defaultH*0.8))
        self.spinnerView.tintColor = UIColor.redColor()
        self.spinnerView.lineWidth = 2
        self.spinnerView.center = CGPointMake(CGRectGetMidX(self.layer.bounds), CGRectGetMidY(self.layer.bounds))
        self.spinnerView.translatesAutoresizingMaskIntoConstraints = false
        self.spinnerView.userInteractionEnabled = false

        self.addSubview(self.spinnerView)
        
        self.addTarget(self, action: #selector(RotationButton.loadingAction), forControlEvents: UIControlEvents.TouchDown)
        
        self.forDisplayButton = UIButton(frame: self.bounds)
        self.forDisplayButton.userInteractionEnabled = false
        self.forDisplayButton.layer.cornerRadius = defaultR
        self.forDisplayButton.backgroundColor = color

        self.addSubview(self.forDisplayButton)
        self.contentColor = color;

//        forDisplayButton.titleEdgeInsets = UIEdgeInsetsMake(0, 7, 0, 0)
//        forDisplayButton.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 5)
        
        forDisplayButton.titleEdgeInsets = UIEdgeInsetsMake(0, -40, 0, 0)
        forDisplayButton.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, -defaultW-20)
        
        self.layer.shadowOffset = CGSizeMake(0, 2);
        self.layer.shadowOpacity = 0.3
    }

    func loadingAction() {
          self.enabled = false
        if (self.isLoading) {
            self.stopLoading()
        }else{
            self.startLoading()
        }
    }
    
    func startLoading(){
        if (btnBackgroundImage == nil) {
            btnBackgroundImage = self.forDisplayButton.backgroundImageForState(UIControlState.Normal)
        }
        
        _isLoading = true;
        self.bgView.hidden = false
        
        let animation = CABasicAnimation(keyPath: "cornerRadius")
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        animation.fromValue = defaultR
        animation.toValue = defaultH*scale*0.5
        animation.duration = 0.3
        self.bgView.layer.cornerRadius = defaultH*scale*0.5
        self.bgView.layer.addAnimation(animation, forKey: "cornerRadius")
        
        self.forDisplayButton.setBackgroundImage(nil, forState: UIControlState.Normal)
        
        UIView.animateWithDuration(0.3, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
//            self.bgView.layer.bounds = CGRectMake(0, 0, self.defaultW*self.scale, self.defaultH*self.scale)
        }) { (Bool) -> Void in
            if self._isLoading {
                UIView.animateWithDuration(0.3, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
                    self.bgView.layer.bounds = CGRectMake(0, 0, self.defaultH*self.scale, self.defaultH*self.scale)
                    self.forDisplayButton.transform = CGAffineTransformMakeScale(0.1, 0.1)
                    self.forDisplayButton.alpha = 0
                    
                    if self._isLoading {
                        self.forDisplayButton.hidden = true
                        self.spinnerView.startAnimating()
                    }
                    }) { (Bool) -> Void in
                       
                        let time: NSTimeInterval = 1
                        let delay = dispatch_time(DISPATCH_TIME_NOW,
                                                  Int64(time * Double(NSEC_PER_SEC)))
                        dispatch_after(delay, dispatch_get_main_queue()) {
                            self.stopLoading()
                        }

                }

            }
        }
    }
    
    func stopLoading(){
        _isLoading = false;
        self.spinnerView.stopAnimating()
        self.forDisplayButton.hidden = false
        
        UIView.animateWithDuration(0.3, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
            self.forDisplayButton.transform = CGAffineTransformMakeScale(1, 1);
            self.forDisplayButton.alpha = 1;
            }) { (Bool) -> Void in
        }
        
        let animation = CABasicAnimation(keyPath: "cornerRadius")
        animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
        animation.fromValue = defaultH*scale*0.5
        animation.toValue = defaultR
        animation.duration = 0.3
        self.bgView.layer.cornerRadius = defaultR
        self.bgView.layer.addAnimation(animation, forKey: "cornerRadius")
        
        UIView.animateWithDuration(0.3, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
//            self.bgView.layer.bounds = CGRectMake(0, 0, self.defaultW*self.scale, self.defaultH*self.scale);
            }) { (Bool) -> Void in
                if !self._isLoading {
                    let animation = CABasicAnimation(keyPath: "cornerRadius")
                    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
                    animation.fromValue = self.bgView.layer.cornerRadius
                    animation.toValue = self.defaultR
                    animation.duration = 0.2
                    self.bgView.layer.cornerRadius = self.defaultR
                    self.bgView.layer.addAnimation(animation, forKey: "cornerRadius")
                    
                    UIView.animateWithDuration(0.3, delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0, options: UIViewAnimationOptions.CurveLinear, animations: { () -> Void in
                        self.bgView.layer.bounds = CGRectMake(0, 0, self.defaultW, self.defaultH);
                        }) { (Bool) -> Void in
                            if !self._isLoading {
                                if (self.btnBackgroundImage != nil) {
                                    self.forDisplayButton.setBackgroundImage(self.btnBackgroundImage, forState: UIControlState.Normal)
                                }
                                self.bgView.hidden = true
                            }
                            self.enabled = true
                    }
                }
        }
    }
}

